package akka.http.scaladsl.marshallers.json4s

import org.json4s.JsonAST.JValue

import scala.language.implicitConversions


//trait Json4sFormat {
//  def fmt[T](implicit  writer: Json4sWriter) = JsonTypeClassWriter[T]
//}
//
//
//trait Json4sReader[T] {
//  def read(resp: JValue): T
//}
//
//
//trait Json4sWriter[T] {
//  def write(body: T): String
//}
//
//
//object Json4sWriter {
//
//  private def wrtr[T](fn: T => String) = new Json4sWriter[T] {
//    def write(body: T): String = fn(body)
//  }
//
//  implicit val StringWriter: Json4sWriter[String] = wrtr(identity)
//  implicit val JValueWriter: Json4sWriter[JValue] = wrtr(jackson.compactJson)
//
//  implicit def OptionWriter[T](implicit writer: Json4sWriter[T]): Json4sWriter[Option[T]] =
//    wrtr(o => o map writer.write getOrElse "")
//
//
//  implicit def JsonTypeClassWriter[T](implicit jsonWriter: org.json4s.Writer[T]): Json4sWriter[T] =
//    wrtr(bd => JValueWriter write jsonWriter.write(bd))
//
//
//  implicit def Json4sFormatsWriter[T](implicit formats: Formats, mf: Manifest[T]): Json4sWriter[T] =
//    wrtr(bd => JValueWriter write Extraction.decompose(bd))
//}
//
//
//object Json4sReader {
//
//  private def rdr[T](fn: String => T): Json4sReader[T] = new Json4sReader[T] {
//    def read(resp: String): T = fn(resp)
//  }
//
//  implicit val StringReader: Json4sReader[String] = rdr(identity)
//  implicit val JValueReader: Json4sReader[JValue] = rdr(r => jackson.parseJson(r))
//  implicit val UnitReader: Json4sReader[Unit] = rdr(_ => ())
//
//  implicit def OptionReader[T](implicit reader: Json4sReader[T]): Json4sReader[Option[T]] = rdr { resp =>
//    try {
//      Option(reader.read(resp))
//    } catch {
//      case _: Throwable => None
//    }
//  }
//
//  implicit def TryReader[T](implicit reader: Json4sReader[T]): Json4sReader[Try[T]] =
//    rdr { resp => Try(reader.read(resp)) }
//
//
//  implicit def JsonTypeClassReader[T](implicit jsonReader: org.json4s.Reader[T]): Json4sReader[T] =
//    rdr(resp => jsonReader.read(JValueReader.read(resp)))
//
//
//  implicit def Json4sFormatsReader[T](implicit formats: org.json4s.Formats, mf: Manifest[T]): Json4sReader[T] =
//    rdr(resp => jackson.parseJson(resp).extract[T])
//
//
//}


import scala.annotation.implicitNotFound

/**
  * Provides the JSON deserialization for type T.
  */
@implicitNotFound(msg = "Cannot find Json4sReader or Json4sFormat type class for ${T}")
trait Json4sReader[T] {
  def read(json: JValue): T
}

object Json4sReader {
  implicit def func2Reader[T](f: JValue => T): Json4sReader[T] = new Json4sReader[T] {
    def read(json: JValue) = f(json)
  }
}

/**
  * Provides the JSON serialization for type T.
  */
@implicitNotFound(msg = "Cannot find Json4sWriter or Json4sFormat type class for ${T}")
trait Json4sWriter[T] {
  def write(obj: T): JValue
}

object Json4sWriter {
  implicit def func2Writer[T](f: T => JValue): Json4sWriter[T] = new Json4sWriter[T] {
    def write(obj: T) = f(obj)
  }
}

/**
  * Provides the JSON deserialization and serialization for type T.
  */
trait Json4sFormat[T] extends Json4sReader[T] with Json4sWriter[T]

/**
  * A special JsonReader capable of reading a legal JSON root object, i.e. either a JSON array or a JSON object.
  */
@implicitNotFound(msg = "Cannot find RootJsonReader or RootJsonFormat type class for ${T}")
trait RootJson4sReader[T] extends Json4sReader[T]

/**
  * A special JsonWriter capable of writing a legal JSON root object, i.e. either a JSON array or a JSON object.
  */
@implicitNotFound(msg = "Cannot find RootJsonWriter or RootJsonFormat type class for ${T}")
trait RootJson4sWriter[T] extends Json4sWriter[T]

/**
  * A special JsonFormat signaling that the format produces a legal JSON root object, i.e. either a JSON array
  * or a JSON object.
  */
trait RootJsonFormat[T] extends Json4sFormat[T] with RootJson4sReader[T] with RootJson4sWriter[T]